﻿using HslCommunication.ModBus;
using HslCommunication;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;

namespace MES
{
    public class Device
    {

        //委托回调
        public delegate void MsgCallBack(string msg);
        public MsgCallBack msgCallBack;

        //通讯
        public ModbusTcpNet PLC = new ModbusTcpNet();
        public bool PLCConnect = false;//连接状态
        public bool PLCReConnect = true;//重复连接
        public string xintiao = "0";


        public NetServer TCPClient = new NetServer();

        public bool TCPConnect = false;//连接状态
        public bool TCPReConnect = true;//重复连接
        public int TCPAliveCheckTime = 20000;//Socket发送固定数据的间隔
        public int TCPCheckTime = 0;//Socket计时

        //参数
        public string Name = "";
        public string CogfigPath = "";
        public string DeviceID = "";
        public string PLC_IP = "";
        public int PLC_Port = 502;
        public string TCP_IP = "";
        public int TCP_Port = 10000;
        public bool LoginState = false;
        public string Sorting = "";
        public string LastTime_Sorting = "";

        public int errorNum = 0;
        public List<int> errorCode = new List<int>();

        public int DelayTime_T1 = 4000;

        public Dictionary<string, int> SendMsgList1 = new Dictionary<string, int>();
        public Dictionary<string, int> SendMsgListCopy = new Dictionary<string, int>();

        /* 
         * 设备触发事件 : 设备设定信息和上报信号给EAP，但EAP没有在T1时间内回复对应信号给设备，设备应发出警告(*1)并以ALARM_REPORT 的message上报EAP（一定时间后设备上报alarm_report消除Clear Alarm）。
         * 设备应提供T1 time设定的功能(T1 time默认值为4秒)。
         * 设备弹窗提示警告信息（可最小化或清除警告）Warning Message：”xxx Event T1 Time Out”，且蜂鸣器短鸣3次。警告期间设备可正常生产，弹窗警告不可影响设备操作。
         * 注释:XXX应根据事件更改名称。
        */
        public int DelayTime_T3 = 0;//当设备上报事件完成后应该要要T3时间，才可以再次向EAP上报相同事件。设备应提供T3 time设定的功能。(T3 time预设时间为2秒，如果T3 时间设定为0，则表示不使用)。
        public List<string> SendEventList = new List<string>();
        public List<int> SendEventListTime = new List<int>();

        public int Idle_Delay_Time = 0;//设备待料判断时间
        public int Idle_WaitTime = 0;
        public bool IdleDelay = false;

        //状态
        public int DeviceState = 0;//1=运行  2=待料   3=停止    4=故障
        public List<string> errorList = new List<string>();
        //1.RUN 正常生产中
        //2.DOWN 故障 
        //3.IDLE 待机 
        //4.STOP 停止 
        //5.INIT 初始化 
        //6.PAUS 暂停 
        //7.FULL 产出满料
        //8.LMTL 材料低位预警
        //9.CHLN 换线中

        //功能
        public Task eventTask;
        public bool eventTaskReturn = false;
        public Task reConnect;
        public bool reConnectReturn = false;

        public int reConnectNum = 0;//用于判断线程是否中断
        public int eventTaskNum = 0;//用于判断线程是否中断
        public Task reStarTask;//用于重新启动线程


        public Device(string Name)
        {
            this.CogfigPath = Directory.GetCurrentDirectory() + @"\data\" + Name + ".ini";
            this.Name = Name;
        }

        public int ReadConfig()
        {
            try
            {
                DeviceID = OpearationTxt.ReadIni("Device", "DeviceID", CogfigPath);
                PLC_IP = OpearationTxt.ReadIni("Device", "PLC_IP", CogfigPath);
                PLC_Port = Convert.ToInt32(OpearationTxt.ReadIni("Device", "PLC_Port", CogfigPath));
                TCP_IP = OpearationTxt.ReadIni("Device", "TCP_IP", CogfigPath);
                TCP_Port = Convert.ToInt32(OpearationTxt.ReadIni("Device", "TCP_Port", CogfigPath));

                DelayTime_T1 = Convert.ToInt32(OpearationTxt.ReadIni("Device", "DelayTime_T1", CogfigPath));
                DelayTime_T3 = Convert.ToInt32(OpearationTxt.ReadIni("Device", "DelayTime_T3", CogfigPath));
                Idle_Delay_Time = Convert.ToInt32(OpearationTxt.ReadIni("Device", "Idle_Delay_Time", CogfigPath));
                TCPAliveCheckTime = Convert.ToInt32(OpearationTxt.ReadIni("Device", "TCPAliveCheckTime", CogfigPath));

                PLCReConnect = Convert.ToBoolean(OpearationTxt.ReadIni("Device", "PLCReConnect", CogfigPath));
                TCPReConnect = Convert.ToBoolean(OpearationTxt.ReadIni("Device", "TCPReConnect", CogfigPath));
            }
            catch
            {
                return -1;
            }
            try
            {
                errorNum = Convert.ToInt32(OpearationTxt.ReadIni("Device", "errorNum", CogfigPath));
                for (int i = 0; i < errorNum; i++)
                {
                    string errorMSG = OpearationTxt.ReadIni("Error", (i + 1).ToString(), CogfigPath);
                    errorList.Add(errorMSG);
                }
            }
            catch
            {
                return -2;
            }

            return 0;
        }
        public int WriteConfig()
        {
            try
            {
                OpearationTxt.WriteIni("Device", "DeviceID", DeviceID, CogfigPath);
                OpearationTxt.WriteIni("Device", "PLC_IP", PLC_IP, CogfigPath);
                OpearationTxt.WriteIni("Device", "PLC_Port", PLC_Port.ToString(), CogfigPath);
                OpearationTxt.WriteIni("Device", "TCP_IP", TCP_IP, CogfigPath);
                OpearationTxt.WriteIni("Device", "TCP_Port", TCP_Port.ToString(), CogfigPath);

                OpearationTxt.WriteIni("Device", "DelayTime_T1", DelayTime_T1.ToString(), CogfigPath);
                OpearationTxt.WriteIni("Device", "DelayTime_T3", DelayTime_T3.ToString(), CogfigPath);
                OpearationTxt.WriteIni("Device", "Idle_Delay_Time", Idle_Delay_Time.ToString(), CogfigPath);
                OpearationTxt.WriteIni("Device", "TCPAliveCheckTime", TCPAliveCheckTime.ToString(), CogfigPath);

                OpearationTxt.WriteIni("Device", "PLCReConnect", PLCReConnect.ToString(), CogfigPath);
                OpearationTxt.WriteIni("Device", "TCPReConnect", TCPReConnect.ToString(), CogfigPath);
            }
            catch
            {
                MessageBox.Show(Name + ": 文件写入失败");
            }
            return 0;
        }
        public void AddSendEventList(string Event)
        {
            try
            {
                lock (this)
                {
                    SendEventList.Add(Event);
                    SendEventListTime.Add(0);
                }
            }
            catch
            {

            }
        }
        public void AddSendMsgList(string Event)
        {
            try
            {
                lock (this)
                {
                    SendMsgList1.Add(Event, 0);
                }
            }
            catch
            {

            }
        }
        public void ConnectPLC()
        {
            PLC.ConnectTimeOut = 500;
            PLC.ReceiveTimeOut = 500;
            PLC.DataFormat = HslCommunication.Core.DataFormat.CDAB;
            PLC.IpAddress = PLC_IP;
            PLC.Port = PLC_Port;
            OperateResult operateResult = PLC.ConnectServer();
            if (operateResult.IsSuccess != true)
            {
                PLCConnect = false;
                return;
            }
            PLCConnect = true;

            Tool.form1.ChangeCommShow(this, PLCConnect, TCPConnect);

        }
        public void ConnectSocket()
        {
            TCPClient.ClientSocket.ReceiveTimeout = 300;
            int Result = TCPClient.Connect(TCP_IP, TCP_Port);
            if (Result == 0)
            {
                TCPConnect = true;
                TCPClient.SetMsgHandle(ReciveMSG_CallBack);
            }
            else
            {
                TCPConnect = false;
            }
            Tool.form1.ChangeCommShow(this, PLCConnect, TCPConnect);
        }
        public void DeviceStar()
        {
            Task.Run((() =>
            {
                ConnectPLC();
                ConnectSocket();
            }));
            eventTask = new Task(EventTaskRun);
            eventTask.Start();
            reConnect = new Task(ReConnection);
            reConnect.Start();
            reStarTask = new Task(ReStarTaskRun);
            reStarTask.Start();
        }
        public void EventTaskRun()
        {
            while (true)
            {
                eventTaskNum = 0;
                lock (this)
                {
                    for (int i = 0; i < SendEventListTime.Count; i++)
                    {
                        SendEventListTime[i] += 250;
                        if (SendEventListTime[i] > DelayTime_T3)
                        {
                            SendEventListTime.RemoveAt(i);
                            SendEventList.RemoveAt(i);
                        }
                    }
                }

                lock (this)
                {
                    //for (int i = 0; i < SendMsgListTime.Count; i++)
                    //{
                    //    SendMsgListTime[i] += 250;
                    //    if (SendMsgListTime[i] > DelayTime_T1)
                    //    {
                    //        //xxx Event T1 Time Out
                    //        //超时事件
                    //        try
                    //        {
                    //            byte[] data = SendEvent.ALARM_REPORT(this, 1, 1, 0, SendMsgList[i] + "  Event T1 Time Out", out string alarmMsg, out string transactionID);
                    //            Tool.form1.DeviceSendMsg(this, data, alarmMsg);
                    //            Tool.SaveLog(this, LogMod.运行记录.ToString(), "报警记录==>" + SendMsgList[i] + "   Event T1 Time Out");
                    //            string sendMSG = SendMsgList[i];
                    //            SendMsgListTime.RemoveAt(i);
                    //            SendMsgList.RemoveAt(i);
                    //            //Task.Run(() =>
                    //            //{
                    //            //    //5秒后发送恢复信号
                    //            //    Thread.Sleep(5000);
                    //            //    data = SendEvent.ALARM_REPORT(this, 2, 1, 0, sendMSG + " Event T1 Time Out", out alarmMsg, out transactionID);
                    //            //    Tool.form1.DeviceSendMsg(this, data, alarmMsg);

                    //            //});
                    //        }
                    //        catch
                    //        {

                    //        }
                    //    }
                    //}

                    SendMsgListCopy = new Dictionary<string, int>(SendMsgList1);
                    foreach (KeyValuePair<string, int> item in SendMsgList1)
                    {
                        SendMsgListCopy[item.Key] += 250;
                        if (SendMsgListCopy[item.Key] > DelayTime_T1)
                        {
                            //xxx Event T1 Time Out
                            //超时事件
                            try
                            {
                                byte[] data = SendEvent.ALARM_REPORT(this, 1, 1, 0, item.Key + "  Event T1 Time Out", out string alarmMsg, out string transactionID);
                                Tool.form1.DeviceSendMsg(this, data, alarmMsg);
                                Tool.SaveLog(this, LogMod.运行记录.ToString(), "报警记录==>" + item.Key + "   Event T1 Time Out");
                                string sendMSG = item.Key;
                                SendMsgListCopy.Remove(item.Key);
                                //Task.Run(() =>
                                //{
                                //    //5秒后发送恢复信号
                                //    Thread.Sleep(5000);
                                //    data = SendEvent.ALARM_REPORT(this, 2, 1, 0, sendMSG + " Event T1 Time Out", out alarmMsg, out transactionID);
                                //    Tool.form1.DeviceSendMsg(this, data, alarmMsg);

                                //});
                            }
                            catch
                            {

                            }
                        }
                    }
                    SendMsgList1 = SendMsgListCopy;


                }

                TCPCheckTime += 250;
                if (TCPCheckTime > TCPAliveCheckTime)
                {
                    ////到达间隔时间，执行Socket连接监测
                    TCPCheckTime = 0;
                    if (TCPConnect)
                    {
                        try
                        {
                            byte[] data = SendEvent.EAP_ALIVE_CHECK(this, out string msg, out string transactionID);
                            Tool.form1.DeviceSendMsg(this, data, msg);
                            AddSendMsgList(transactionID);
                        }
                        catch
                        {
                            TCPConnect = false;
                            if (TCPReConnect)
                            {
                                Tool.SaveLog(this, LogMod.运行记录.ToString(), "报警记录==>" + " EAP通讯断开连接");
                                Tool.form1.AddMSG(this, "EAP通讯断开连接");
                            }
                            Tool.form1.ChangeCommShow(this, PLCConnect, TCPConnect);
                        }
                    }

                    //try
                    //{
                    //    Stopwatch stopwatch = new Stopwatch();
                    //    stopwatch.Start();
                    //    bool operateResult = PLC.ReadInt16(xintiao).IsSuccess;
                    //    if (operateResult == false)
                    //    {
                    //        PLCConnect = false;
                    //        if (PLCReConnect)
                    //        {
                    //            Tool.SaveLog(this, LogMod.运行记录.ToString(), "报警记录==>" + " ModBus通讯断开连接");
                    //            Tool.form1.AddMSG(this, "ModBus通讯断开连接");
                    //        }
                    //        Tool.form1.ChangeCommShow(this, PLCConnect, TCPConnect);
                    //    }
                    //    stopwatch.Stop();
                    //    Tool.form1.AddMSG(this, stopwatch.ElapsedMilliseconds.ToString());

                    //}
                    //catch
                    //{
                    //}
                }
                if (eventTaskReturn)
                {
                    return;
                }

                Thread.Sleep(250);
            }
        }
        public void ReConnection()
        {
            while (true)
            {
                reConnectNum = 0;
                if (TCPConnect == false && TCPReConnect == true)
                {
                    //执行TCP重连
                    ConnectSocket();
                }

                if (PLCConnect == false && PLCReConnect == true)
                {
                    //执行PLC重连
                    ConnectPLC();
                }
                Thread.Sleep(2500);
                if (reConnectReturn)
                {
                    return;
                }
            }
        }
        public void ReStarTaskRun()
        {
            while (true)
            {
                eventTaskNum++;
                if (eventTaskNum > 10)
                {
                    eventTaskReturn = true;
                    Thread.Sleep(2000);
                    eventTaskReturn = false;
                    eventTask = new Task(EventTaskRun);
                    eventTask.Start();
                    eventTaskNum = 0;
                    Tool.form1.AddMSG(this, "线程EventTaskRun重启");
                }
                if (reConnectNum > 10)
                {
                    reConnectReturn = true;
                    reConnect = new Task(ReConnection);
                    Thread.Sleep(2500);
                    reConnectReturn = false;
                    reConnect.Start();
                    reConnectNum = 0;
                    Tool.form1.AddMSG(this, "线程ReConnection重启");
                }

                Thread.Sleep(1000);
            }
        }
        public int CloseSocket()
        {
            try
            {
                TCPClient.ClientSocket.Disconnect(true);
                return 0;
            }
            catch
            {
                return -1;
            }
        }
        public void CloseModBus()
        {
            PLC.ConnectClose();
        }

        ////////////回调////////////////////////回调////////////////////////回调////////////////////////回调////////////////////////回调////////////////////////回调////////////
        /// <summary>
        /// 收到msg的回调
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="msg"></param>
        public void ReciveMSG_CallBack(string ip, string msg)
        {
            msgCallBack(msg);
        }

        public void SetMsgCallBackHandle(MsgCallBack CallBack)
        {
            this.msgCallBack = new MsgCallBack(CallBack);
        }

    }
    /// <summary>
    /// 扫码枪类
    /// </summary>
    public class ScanDevice
    {
        //委托回调
        public delegate void MsgCallBack(string msg);
        public MsgCallBack msgCallBack;

        //参数
        public string CogfigPath;
        public string Name;
        public NetServer TCPClient = new NetServer();
        public string TCP_IP = "127.0.0.1";
        public int TCP_Port = 10000;
        public bool TCPConnect = false;
        public string ScanMSG = "0";

        public ScanDevice(string Name)
        {
            this.CogfigPath = Directory.GetCurrentDirectory() + @"\data\" + Name + ".ini";
            this.Name = Name;
        }
        public int ConnectSocket()
        {
            TCPClient.ClientSocket.ReceiveTimeout = 300;
            int Result = TCPClient.Connect(TCP_IP, TCP_Port);
            if (Result == 0)
            {
                TCPConnect = true;
                TCPClient.SetMsgHandle(ReciveMSG_CallBack);
                return 0;
            }
            else
            {
                TCPConnect = false;
                return -1;
            }
        }
        public void SetMsgCallBackHandle(MsgCallBack CallBack)
        {
            this.msgCallBack = new MsgCallBack(CallBack);
        }
        public void ReciveMSG_CallBack(string ip, string msg)
        {
            msgCallBack(msg);
        }
        public int CloseSocket()
        {
            try
            {
                TCPClient.ClientSocket.Disconnect(true);
                TCPConnect = false;
                return 0;
            }
            catch
            {
                return -1;
            }
        }
        public int ReadConfig()
        {
            try
            {
                TCP_IP = OpearationTxt.ReadIni("Device", "TCP_IP", CogfigPath);
                TCP_Port = Convert.ToInt32(OpearationTxt.ReadIni("Device", "TCP_Port", CogfigPath));
            }
            catch
            {
                return -1;
            }
            return 0;
        }

        public int WriteConfig()
        {
            try
            {
                OpearationTxt.WriteIni("Device", "TCP_IP", TCP_IP, CogfigPath);
                OpearationTxt.WriteIni("Device", "TCP_Port", TCP_Port.ToString(), CogfigPath);
            }
            catch
            {
                MessageBox.Show(Name + ": 文件写入失败");
            }
            return 0;
        }
    }
}
